//sets all private functions to public for unit testing
#define private public
#include "LifeCheckerTest.h"
#include <iostream>

using namespace std;

LifeCheckerTest::LifeCheckerTest(){
  testChecker = new LifeChecker(3, 4);
}

LifeCheckerTest::~LifeCheckerTest(){
  testChecker->~LifeChecker();
}

//if the value in the current X is being returned
//true if succeed
bool LifeCheckerTest::getCurXTest(){
  //checks if default is 0
  if(!getCurTestError('X', 0)){return false;}

  //checks various values being set
  testChecker->curX = 1;
  if(!getCurTestError('X', 1)){return false;}

  testChecker->curX = 20;
  if(!getCurTestError('X', 20)){return false;}

  testChecker->curX = 3;
  if(!getCurTestError('X', 3)){return false;}

  //reset to 0
  testChecker->curX = 0;

  return true;
}

//if the value in the current Y is being returned
//true if succeed
bool LifeCheckerTest::getCurYTest(){
  //checks if default is 0
  if(!getCurTestError('Y', 0)){return false;}

  //checks various values being set
  testChecker->curY = 1;
  if(!getCurTestError('Y', 1)){return false;}

  testChecker->curY = 20;
  if(!getCurTestError('Y', 20)){return false;}

  testChecker->curY = 3;
  if(!getCurTestError('Y', 3)){return false;}

  //reset to 0
  testChecker->curY = 0;
  return true;
}

//if it the value of curX is changing to the input
//true if succeed
bool LifeCheckerTest::setCurXTest(){
  //checks if sets various values
  testChecker->setCurX(1);
  if(!setCurTestError('X', 1)){return false;}

  testChecker->setCurX(20);
  if(!setCurTestError('X', 20)){return false;}

  testChecker->setCurX(0);
  if(!setCurTestError('X', 0)){return false;}

  testChecker->setCurX(9999);
  if(!setCurTestError('X', 9999)){return false;}

  testChecker->setCurX(0);
  return true;
}

//if it the value of curY is changing to the input
//true if succeed
bool LifeCheckerTest::setCurYTest(){
  //checks if sets various values
  testChecker->setCurY(1);
  if(!setCurTestError('Y', 1)){return false;}

  testChecker->setCurY(20);
  if(!setCurTestError('Y', 20)){return false;}

  testChecker->setCurY(0);
  if(!setCurTestError('Y', 0)){return false;}

  testChecker->setCurY(9999);
  if(!setCurTestError('Y', 9999)){return false;}

  testChecker->setCurY(0);
  return true;
}

//if it will only check the cell above and if it
//will return a true for alive
//true if succeed
bool LifeCheckerTest::lifeUpTest(){
  testChecker->setCurX(0);
  testChecker->setCurY(0);

  //checks when X and Y are 0
  //should be false
  if(!lifeDirectionTestError(1, false)){return false;}

  //when X is not 0, but Y is 0
  //should be false
  testChecker->setCurX(1);
  if(!lifeDirectionTestError(1, false)){return false;}

  //when both X and Y are not zero
  //but there is a barren cell above
  //should be false
  testChecker->setCurX(1);
  testChecker->setCurY(1);
  if(!lifeDirectionTestError(1, false)){return false;}

  //when both X and Y are not zero
  //and a alive cell above
  //should be true
  testChecker->gameBoard->setLifeBoard(true, 1, 0);
  if(!lifeDirectionTestError(1, true)){return false;}
  testChecker->gameBoard->resetLifeBoard();

  //when X is 0 and Y is not zero
  //and a barren cell above
  //should be false
  testChecker->setCurX(0);
  if(!lifeDirectionTestError(1, false)){return false;}

  //when X is 0 and Y is not zero
  //and an alive cell above
  //should be true
  testChecker->gameBoard->setLifeBoard(true, 0, 0);
  if(!lifeDirectionTestError(1, true)){return false;}
  testChecker->gameBoard->resetLifeBoard();

  return true;
}


//if it will only check the cell below and if it
//will return a true for alive
//true if succeed
bool LifeCheckerTest::lifeDownTest(){
  testChecker->setCurX(0);
  testChecker->setCurY(0);

  //when X is 0 and Y is 0
  //barren cell below
  //should be false
  if(!lifeDirectionTestError(6, false)){return false;}

  //when X is 0 and Y is 0
  //alive cell below
  //should be true;
  testChecker->gameBoard->setLifeBoard(true, 0, 1);
  if(!lifeDirectionTestError(6, true)){return false;}
  testChecker->gameBoard->resetLifeBoard();

  //when X is 0 and Y is at Range limit
  //should be false
  testChecker->setCurY(testChecker->gameBoard->getLifeBoardYRange() - 1);
  if(!lifeDirectionTestError(6, false)){return false;}

  //when X is at range limit and Y is at range limit
  //should be false
  testChecker->setCurX(testChecker->gameBoard->getLifeBoardXRange() - 1);
  if(!lifeDirectionTestError(6, false)){return false;}

  //when X is not 0 and Y is zero
  //barren cell below
  //should be false
  testChecker->setCurX(1);
  testChecker->setCurY(0);
  if(!lifeDirectionTestError(6, false)){return false;}

  //when X is not 0 and Y is zero
  //alive cell below
  //should be true
  testChecker->gameBoard->setLifeBoard(true, 1, 1);
  if(!lifeDirectionTestError(6, true)){return false;}
  testChecker->gameBoard->resetLifeBoard();

  //when both X and Y are not zero
  //barren below
  //should be false
  testChecker->setCurY(1);
  if(!lifeDirectionTestError(6, false)){return false;}

  //when both X and Y are not zero
  //alive below
  //should be true
  testChecker->gameBoard->setLifeBoard(true, 1, 2);
  if(!lifeDirectionTestError(6, true)){return false;}
  testChecker->gameBoard->resetLifeBoard();

  //when X is 0 and Y is not zero
  //barren below
  //should be false
  testChecker->setCurX(0);
  if(!lifeDirectionTestError(6, false)){return false;}

  //when X is 0 and Y is not zero
  //alive below
  //should be true
  testChecker->gameBoard->setLifeBoard(true, 0, 2);
  if(!lifeDirectionTestError(6, true)){return false;}
  testChecker->gameBoard->resetLifeBoard();

  return true;
}


//if it will only check the cell to the right and if it
//will return a true for alive
//true if succeed
bool LifeCheckerTest::lifeRightTest(){
  testChecker->setCurX(0);
  testChecker->setCurY(0);

  //when X and Y are 0
  //barren right
  //should be false
  if(!lifeDirectionTestError(4, false)){return false;}

  //When X is 0 and Y is not 0
  //barren right
  //should be false
  testChecker->setCurY(1);
  if(!lifeDirectionTestError(4, false)){return false;}

  //when X and Y are not 0
  //barren right
  //should be false
  testChecker->setCurX(1);
  if(!lifeDirectionTestError(4, false)){return false;}

  //when X at limit and y 0
  //should be false
  testChecker->setCurX(testChecker->gameBoard->getLifeBoardXRange() - 1);
  testChecker->setCurY(0);
  if(!lifeDirectionTestError(4, false)){return false;}

  //when X and Y at limit
  //should be false
  testChecker->setCurY(testChecker->gameBoard->getLifeBoardYRange() - 1);
  if(!lifeDirectionTestError(4, false)){return false;}

  //when X and Y are 0
  //alive right
  //should be true
  testChecker->setCurX(0);
  testChecker->setCurY(0);
  testChecker->gameBoard->setLifeBoard(true, 1, 0);
  if(!lifeDirectionTestError(4, true)){return false;}
  testChecker->gameBoard->resetLifeBoard();

  //when X is 0 and Y is not 0
  //alive right
  //Should be true
  testChecker->setCurY(1);
  testChecker->gameBoard->setLifeBoard(true, 1, 1);
  if(!lifeDirectionTestError(4, true)){return false;}
  testChecker->gameBoard->resetLifeBoard();

  //when X and Y are not 0
  //alive right
  //should be true
  testChecker->setCurX(1);
  testChecker->gameBoard->setLifeBoard(true, 2, 1);
  if(!lifeDirectionTestError(4, true)){return false;}
  testChecker->gameBoard->resetLifeBoard();

  return true;
}


//if it will only check the cell to the left and if it
//will return a true for alive
//true if succeed
bool LifeCheckerTest::lifeLeftTest(){
  testChecker->setCurX(0);
  testChecker->setCurY(0);

  //When X and Y are 0
  //should be false
  if(!lifeDirectionTestError(3, false)){return false;}

  //When X is 0 and Y is not
  //should be false
  testChecker->setCurY(1);
  if(!lifeDirectionTestError(3, false)){return false;}

  //when X is not zero and Y is not
  //barren on the left
  //should be false
  testChecker->setCurX(1);
  if(!lifeDirectionTestError(3, false)){return false;}

  //when X is not zero and Y is 0
  //barren on the left
  //should be false
  testChecker->setCurY(0);
  if(!lifeDirectionTestError(3, false)){return false;}

  //when X is not zero and Y is 0
  //alive on the left
  //should be true
  testChecker->gameBoard->setLifeBoard(true, 0, 0);
  if(!lifeDirectionTestError(3, true)){return false;}
  testChecker->gameBoard->resetLifeBoard();

  //when X is not zero and Y is not zero
  //alive on the left
  //should be true
  testChecker->setCurY(1);
  testChecker->gameBoard->setLifeBoard(true, 0, 1);
  if(!lifeDirectionTestError(3, true)){return false;}
  testChecker->gameBoard->resetLifeBoard();

  return true;
}


//if it will only check the cell above
//to the right and if it will
//return a true for alive
//true if succeed
bool LifeCheckerTest::lifeUpRightTest(){
  testChecker->setCurX(0);
  testChecker->setCurY(0);

  //When X and Y are 0
  //should be false
  if(!lifeDirectionTestError(2, false)){return false;}

  //When X is 0 and Y is not
  //barren on upper right
  //should be false
  testChecker->setCurY(1);
  if(!lifeDirectionTestError(2, false)){return false;}

  //when X is not zero and Y is zero
  //should be false
  testChecker->setCurX(1);
  testChecker->setCurY(0);
  if(!lifeDirectionTestError(2, false)){return false;}

  //when X is not zero and Y is not zero
  //barren in sector
  //should be false
  testChecker->setCurY(1);
  if(!lifeDirectionTestError(2, false)){return false;}

  //when X is at limit and Y is 0
  //should be false
  testChecker->setCurX(testChecker->gameBoard->getLifeBoardXRange() - 1);
  testChecker->setCurY(0);
  if(!lifeDirectionTestError(2, false)){return false;}

  //when X is at limit and Y is not at zero
  //should be false
  testChecker->setCurY(1);
  if(!lifeDirectionTestError(2, false)){return false;}

  //when X is 0 and Y is not
  //alive in sector
  //should be true
  testChecker->setCurX(0);
  testChecker->gameBoard->setLifeBoard(true, 1, 0);
  if(!lifeDirectionTestError(2, true)){return false;}
  testChecker->gameBoard->resetLifeBoard();

  //when X is not zero and Y is not zero
  //alive in sector
  //should be true
  testChecker->setCurX(1);
  testChecker->gameBoard->setLifeBoard(true, 2, 0);
  if(!lifeDirectionTestError(2, true)){return false;}
  testChecker->gameBoard->resetLifeBoard();

  return true;
}

//if it will only check the cell above
//to the left and if it will
//return a true for alive
//true if succeed
bool LifeCheckerTest::lifeUpLeftTest(){
  testChecker->setCurX(0);
  testChecker->setCurY(0);

  //when X and Y are 0
  //should be false
  if(!lifeDirectionTestError(0, false)){return false;}

  //when X is 0 and Y is not
  //should be false
  testChecker->setCurY(1);
  if(!lifeDirectionTestError(0, false)){return false;}

  //when X and Y are not 0
  //barren cell in sector
  //should be false
  testChecker->setCurX(1);
  if(!lifeDirectionTestError(0, false)){return false;}

  //when X is not 0 and Y is 0
  //should be false
  testChecker->setCurY(0);
  if(!lifeDirectionTestError(0, false)){return false;}

  //when X and Y are not 0
  //alive cell in sector
  //should be true
  testChecker->setCurY(1);
  testChecker->gameBoard->setLifeBoard(true, 0, 0);
  if(!lifeDirectionTestError(0, true)){return false;}
  testChecker->gameBoard->resetLifeBoard();

  return true;
}

//if it will only check the cell below
//to the right and if it will
//return a true for alive
//true if succeed
bool LifeCheckerTest::lifeDownRightTest(){
  testChecker->setCurX(0);
  testChecker->setCurY(0);

  //when X and Y are 0
  //barren in sector
  //should be false
  if(!lifeDirectionTestError(7, false)){return false;}

  //when X is 0 and Y is not
  //barren in sector
  //should be false
  testChecker->setCurY(1);
  if(!lifeDirectionTestError(7, false)){return false;}

  //when X is not 0 and Y is not 0
  //barren in sector
  //should be false
  testChecker->setCurX(0);
  if(!lifeDirectionTestError(7, false)){return false;}

  //when X is at limit and Y is at 0
  //should be false
  testChecker->setCurX(testChecker->gameBoard->getLifeBoardXRange() - 1);
  testChecker->setCurY(0);
  if(!lifeDirectionTestError(7, false)){return false;}

  //when X is at limit and Y is at limit
  //should be false
  testChecker->setCurY(testChecker->gameBoard->getLifeBoardYRange() - 1);
  if(!lifeDirectionTestError(7, false)){return false;}

  //when X is not 0 and Y is 0
  //barren sector
  //should be false
  testChecker->setCurX(1);
  testChecker->setCurY(0);
  if(!lifeDirectionTestError(7, false)){return false;}

  //when X and Y are 0
  //alive in sector
  //should be true
  testChecker->setCurX(0);
  testChecker->gameBoard->setLifeBoard(true, 1, 1);
  if(!lifeDirectionTestError(7, true)){return false;}
  testChecker->gameBoard->resetLifeBoard();

  //when X is 0 and Y is not
  //alive in sector
  //should be true
  testChecker->setCurY(1);
  testChecker->gameBoard->setLifeBoard(true, 1, 2);
  if(!lifeDirectionTestError(7, true)){return false;}
  testChecker->gameBoard->resetLifeBoard();

  //when X is not 0 and Y is not 0
  //alive in sector
  //should be true
  testChecker->setCurX(1);
  testChecker->gameBoard->setLifeBoard(true, 2, 2);
  if(!lifeDirectionTestError(7, true)){return false;}
  testChecker->gameBoard->resetLifeBoard();

  return true;
}

//if it will only check the cell below
//to the left and if it will
//return a true for alive
//true if succeed
bool LifeCheckerTest::lifeDownLeftTest(){
  testChecker->setCurX(0);
  testChecker->setCurY(0);

  //When X and Y are 0
  //should be false
  if(!lifeDirectionTestError(5, false)){return false;}

  //when X is 0 and Y is not
  //should be false
  testChecker->setCurY(1);
  if(!lifeDirectionTestError(5, false)){return false;}

  //when X is not and Y is not
  //barren in sector
  //should be false
  testChecker->setCurX(1);
  if(!lifeDirectionTestError(5, false)){return false;}

  //when X is not and Y is 0
  //barren in sector
  //should be false
  testChecker->setCurY(0);
  if(!lifeDirectionTestError(5, false)){return false;}

  //when X is at range and Y is not
  //barren sector
  //should be false
  testChecker->setCurY(1);
  testChecker->setCurX(testChecker->gameBoard->getLifeBoardXRange() - 1);
  if(!lifeDirectionTestError(5, false)){return false;}

  //when X is at range and Y is at range
  //should be false
  testChecker->setCurY(testChecker->gameBoard->getLifeBoardYRange() - 1);
  if(!lifeDirectionTestError(5, false)){return false;}

  //when X is at 0 and Y is at range
  //should be false
  testChecker->setCurX(0);
  if(!lifeDirectionTestError(5, false)){return false;}

  //when x is not and Y is not
  //alive in sector
  //should be true
  testChecker->setCurX(1);
  testChecker->setCurY(1);
  testChecker->gameBoard->setLifeBoard(true, 0, 2);
  if(!lifeDirectionTestError(5, true)){return false;}
  testChecker->gameBoard->resetLifeBoard();

  //when X is not and Y is 0
  //alive in sector
  //should be true
  testChecker->setCurY(0);
  testChecker->gameBoard->setLifeBoard(true, 0, 1);
  if(!lifeDirectionTestError(5, true)){return false;}
  testChecker->gameBoard->resetLifeBoard();

  //when X is at range and Y is not
  //alive sector
  //should be true
  testChecker->setCurX(testChecker->gameBoard->getLifeBoardXRange() - 1);
  testChecker->gameBoard->setLifeBoard(true, testChecker->gameBoard->getLifeBoardXRange() - 2, 1);
  if(!lifeDirectionTestError(5, true)){return false;}
  testChecker->gameBoard->resetLifeBoard();

  return true;
}


//if the amount of trues or falses call for
//a cell to be living or dead ensure that it will
//send the true for alive or false for dead
//true if succeed
bool LifeCheckerTest::aliveTest(){
  testChecker->setCurX(1);
  testChecker->setCurY(1);

  /***zero neighbors - false***/
  if(!aliveTestError(false)){
      cout << "N: " << 0 << endl;
      return false;
  }

  /***One neighbor - false***/
  testChecker->gameBoard->setLifeBoard(true, 0, 1);
  if(!aliveTestError(false)){
      cout << "N: " << 1 << endl;
      return false;
  }

  /***two neighbors and dead - false***/
  testChecker->gameBoard->setLifeBoard(true, 2, 1);
  if(!aliveTestError(false)){
      cout << "N: " << 2 << "(1)" << endl;
      return false;
  }

  /***two neighbor and alive - true***/
  testChecker->gameBoard->setLifeBoard(true, 1, 1);
  if(!aliveTestError(true)){
      cout << "N: " << 2 << "(2)" << endl;
      return false;
  }

  /***three neighbors - true***/
  testChecker->gameBoard->setLifeBoard(true, 0, 2);
  if(!aliveTestError(true)){
      cout << "N: " << 3 << endl;
      return false;
  }

  /***four neighbors - false***/
  testChecker->gameBoard->setLifeBoard(true, 1, 0);
  if(!aliveTestError(false)){
      cout << "N: " << 4 << endl;
      return false;
  }

  /***five neighbors - false***/
  testChecker->gameBoard->setLifeBoard(true, 0, 0);
  if(!aliveTestError(false)){
      cout << "N: " << 5 << endl;
      return false;
  }

  /***six neighbors - false***/
  testChecker->gameBoard->setLifeBoard(true, 0, 2);
  if(!aliveTestError(false)){
      cout << "N: " << 6 << endl;
      return false;
  }

  /***seven neighbors - false***/
  testChecker->gameBoard->setLifeBoard(true, 1, 2);
  if(!aliveTestError(false)){
      cout << "N: " << 7 << endl;
      return false;
  }

  /***eight neighbors- false***/
  testChecker->gameBoard->setLifeBoard(true, 2, 2);
  if(!aliveTestError(false)){
      cout << "N: " << 8 << endl;
      return false;
  }

  return true;
}

//determines what axis the test is for and checks if the expected value
//is recieved from function
//true if succeed
bool LifeCheckerTest::getCurTestError(char axis, int check){
  if(axis == 'X'){
    if(check != testChecker->getCurX()){
      cout << "Error getCur" << axis << ": " << testChecker->getCurX() << endl;
      return false;
    }
  }
  else{
    if(check != testChecker->getCurY()){
      cout << "Error getCur" << axis << ": " << testChecker->getCurY() << endl;
      return false;
    }
  }

  return true;
}

//determines what axis the test is for and checks if the expected value
//is recieved from function
//true if succeed
bool LifeCheckerTest::setCurTestError(char axis, int check){
  if(axis == 'X'){
    if(check != testChecker->getCurX()){
      cout << "Error setCur" << axis << ": " << testChecker->getCurX() << endl;
      return false;
    }
  }
  else{
    if(check != testChecker->getCurY()){
      cout << "Error setCur" << axis << ": " << testChecker->getCurY() << endl;
      return false;
    }
  }

  return true;
}

//determines what sector the test is checking of the gameboard and determines which
//function to use to check if the cell in that sector is alive
//checks the expected with the value recieved from the determined function
//true if succeed
bool LifeCheckerTest::lifeDirectionTestError(int map, bool check){
  switch(map){
    case 0:
      if(check != testChecker->lifeUpLeftChecker()){
        cout << "Error UP LEFT" << endl;
        return false;
      }
      break;
    case 1:
      if(check != testChecker->lifeUpChecker()){
        cout << "Error UP" << endl;
        return false;
      }
      break;
    case 2:
      if(check != testChecker->lifeUpRightChecker()){
        cout << "Error UP RIGHT" << endl;
        return false;
      }
      break;
    case 3:
      if(check != testChecker->lifeLeftChecker()){
        cout << "Error LEFT" << endl;
        return false;
      }
      break;
    case 4:
      if(check != testChecker->lifeRightChecker()){
        cout << "Error RIGHT" << endl;
        return false;
      }
      break;
    case 5:
      if(check != testChecker->lifeDownLeftChecker()){
        cout << "Error DOWN LEFT" << endl;
        return false;
      }
      break;
    case 6:
      if(check != testChecker->lifeDownChecker()){
        cout << "Error DOWN" << endl;
        return false;
      }
      break;
    case 7:
      if(check != testChecker->lifeDownRightChecker()){
        cout << "Error DOWN RIGHT" << endl;
        return false;
      }
      break;
    default:
      cout << "No test specified in direction test." << endl;
  }

  return true;
}

//calls the is Alive function to determine based on the expected value if the
//cell at a given location is alive at the time
//true if succeed
bool LifeCheckerTest::aliveTestError(bool check){
  /*if(check != testChecker->isAlive(testChecker->gameBoard)){
      cout << "Error in AliveTest" << endl;
      return false;
      }
  */
  return true;
}
